package com.yalantis.ucrop.util;

import ohos.multimodalinput.event.TouchEvent;

public class RotationGestureDetector {

    private static final int INVALID_POINTER_INDEX = -1;

    private float fX, fY, sX, sY;

    private int mPointerIndex1, mPointerIndex2;
    private float mAngle;
    private boolean mIsFirstTouch;

    private final OnRotationGestureListener mListener;

    public RotationGestureDetector(OnRotationGestureListener listener) {
        mListener = listener;
        mPointerIndex1 = INVALID_POINTER_INDEX;
        mPointerIndex2 = INVALID_POINTER_INDEX;
    }

    public float getAngle() {
        return mAngle;
    }

    public void onTouchEvent(TouchEvent event) {
        switch (event.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                sX = event.getPointerPosition(0).getX();
                sY = event.getPointerPosition(0).getY();
                mPointerIndex1 = event.getPointerId(0);
                mAngle = 0;
                mIsFirstTouch = true;
                break;
            case TouchEvent.OTHER_POINT_DOWN:
                fX = event.getPointerPosition(0).getX();
                fY = event.getPointerPosition(0).getY();
                mPointerIndex2 = event.getPointerId(event.getIndex());
                mAngle = 0;
                mIsFirstTouch = true;
                break;
            case TouchEvent.POINT_MOVE:
                if (mPointerIndex1 != INVALID_POINTER_INDEX && mPointerIndex2 != INVALID_POINTER_INDEX && event.getPointerCount() > mPointerIndex2) {
                    float nfX, nfY, nsX, nsY;

                    nsX = event.getPointerPosition(mPointerIndex1).getX();
                    nsY = event.getPointerPosition(mPointerIndex1).getY();
                    nfX = event.getPointerPosition(mPointerIndex2).getX();
                    nfY = event.getPointerPosition(mPointerIndex2).getY();

                    if (mIsFirstTouch) {
                        mAngle = 0;
                        mIsFirstTouch = false;
                    } else {
                        calculateAngleBetweenLines(fX, fY, sX, sY, nfX, nfY, nsX, nsY);
                    }

                    if (mListener != null) {
                        mListener.onRotation(this);
                    }
                    fX = nfX;
                    fY = nfY;
                    sX = nsX;
                    sY = nsY;
                }
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                mPointerIndex1 = INVALID_POINTER_INDEX;
                break;
            case TouchEvent.OTHER_POINT_UP:
                mPointerIndex2 = INVALID_POINTER_INDEX;
                break;
        }
    }

    private void calculateAngleBetweenLines(float fx1, float fy1, float fx2, float fy2,
                                            float sx1, float sy1, float sx2, float sy2) {
        calculateAngleDelta(
                (float) Math.toDegrees((float) Math.atan2((NumCalcUtil.subtract(fy1 , fy2))
                        , (NumCalcUtil.subtract(fx1 , fx2)))),
                (float) Math.toDegrees((float) Math.atan2((NumCalcUtil.subtract(sy1 , sy2))
                        , (NumCalcUtil.subtract(sx1 , sx2)))));
    }

    private void calculateAngleDelta(float angleFrom, float angleTo) {
        mAngle = NumCalcUtil.subtract(angleTo % 360.0f , angleFrom % 360.0f);

        if (mAngle < -180.0f) {
            mAngle = NumCalcUtil.add(mAngle , 360.0f);
        } else if (mAngle > 180.0f) {
            mAngle = NumCalcUtil.subtract(mAngle , 360.0f);
        }

    }

    public static class SimpleOnRotationGestureListener implements OnRotationGestureListener {

        @Override
        public void onRotation(RotationGestureDetector rotationDetector) {
        }
    }

    public interface OnRotationGestureListener {
        void onRotation(RotationGestureDetector rotationDetector);
    }

}